package viz.flutter.plugin.paddle_face

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.preference.PreferenceManager
import android.util.Log
import com.baidu.paddle.lite.demo.face_detection.Predictor
import com.baidu.paddle.lite.demo.face_detection.Utils
import com.baidu.paddle.lite.demo.face_detection.config.Config
import com.baidu.paddle.lite.demo.face_detection.preprocess.Preprocess
import com.baidu.paddle.lite.demo.face_detection.visual.Visualize
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import java.io.File
import java.io.InputStream

class PaddleFaceDelegate(private val activity: Activity,
                         private var pendingResult: MethodChannel.Result? = null,
                         private var methodCall: MethodCall? = null
) : PluginRegistry.ActivityResultListener {
    private val TAG = "PaddleFaceDelegate"

    val predictor = Predictor()
    val preprocess = Preprocess()
    val visualize = Visualize()
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
        return true
    }

    fun initConfig(preprocess: Preprocess): Config {
        val config = Config()
        val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
        var settingsChanged = false
        val model_path = sharedPreferences.getString(activity.getString(R.string.MODEL_PATH_KEY),
                activity.getString(R.string.MODEL_PATH_DEFAULT))
        val label_path = sharedPreferences.getString(activity.getString(R.string.LABEL_PATH_KEY),
                activity.getString(R.string.LABEL_PATH_DEFAULT))
        val image_path = sharedPreferences.getString(activity.getString(R.string.IMAGE_PATH_KEY),
                activity.getString(R.string.IMAGE_PATH_DEFAULT))
        settingsChanged = settingsChanged or !model_path.equals(config.modelPath, ignoreCase = true)
        settingsChanged = settingsChanged or !label_path.equals(config.labelPath, ignoreCase = true)
        settingsChanged = settingsChanged or !image_path.equals(config.imagePath, ignoreCase = true)
        val cpu_thread_num = sharedPreferences.getString(activity.getString(R.string.CPU_THREAD_NUM_KEY),
                activity.getString(R.string.CPU_THREAD_NUM_DEFAULT))!!.toInt()
        settingsChanged = settingsChanged or (cpu_thread_num != config.cpuThreadNum)
        val cpu_power_mode = sharedPreferences.getString(activity.getString(R.string.CPU_POWER_MODE_KEY),
                activity.getString(R.string.CPU_POWER_MODE_DEFAULT))
        settingsChanged = settingsChanged or !cpu_power_mode.equals(config.cpuPowerMode, ignoreCase = true)
        val input_color_format = sharedPreferences.getString(activity.getString(R.string.INPUT_COLOR_FORMAT_KEY),
                activity.getString(R.string.INPUT_COLOR_FORMAT_DEFAULT))
        settingsChanged = settingsChanged or !input_color_format.equals(config.inputColorFormat, ignoreCase = true)
        val input_shape = Utils.parseLongsFromString(sharedPreferences.getString(activity.getString(R.string.INPUT_SHAPE_KEY),
                activity.getString(R.string.INPUT_SHAPE_DEFAULT)), ",")
        val input_mean = Utils.parseFloatsFromString(sharedPreferences.getString(activity.getString(R.string.INPUT_MEAN_KEY),
                activity.getString(R.string.INPUT_MEAN_DEFAULT)), ",")
        val input_std = Utils.parseFloatsFromString(sharedPreferences.getString(activity.getString(R.string.INPUT_STD_KEY), activity.getString(R.string.INPUT_STD_DEFAULT)), ",")
        settingsChanged = settingsChanged or (input_shape.size != config.inputShape.size)
        settingsChanged = settingsChanged or (input_mean.size != config.inputMean.size)
        settingsChanged = settingsChanged or (input_std.size != config.inputStd.size)
        if (!settingsChanged) {
            for (i in input_shape.indices) {
                settingsChanged = settingsChanged or (input_shape[i] != config.inputShape.get(i))
            }
            for (i in input_mean.indices) {
                settingsChanged = settingsChanged or (input_mean[i] != config.inputMean.get(i))
            }
            for (i in input_std.indices) {
                settingsChanged = settingsChanged or (input_std[i] != config.inputStd.get(i))
            }
        }

        if (settingsChanged) {
            config.init(model_path, label_path, image_path, cpu_thread_num, cpu_power_mode,
                    input_color_format, input_shape, input_mean, input_std)
        }
        return config
    }

    fun getFaceCount(imagePath: String) {
        val startTime = System.currentTimeMillis()
        var facesCount = 0
        val config = initConfig(preprocess)
        config.imagePath = imagePath
        predictor.init(activity, config)
        if(predictor.isLoaded()) {
            if(config.imagePath.isNotEmpty()) {
                var image: Bitmap? = null
                // read test image file from custom file_paths if the first character of mode file_paths is '/', otherwise read test
                // image file from assets
                // read test image file from custom file_paths if the first character of mode file_paths is '/', otherwise read test
                // image file from assets
                image = if (!config.imagePath.substring(0, 1).equals("/")) {
                    val imageStream: InputStream = activity.assets.open(config.imagePath)
                    BitmapFactory.decodeStream(imageStream)
                } else {
                    if (!File(config.imagePath).exists()) {
                        pendingResult?.error("-3","图片不存在",null)
                        clearMethodCallAndResult()
                        return
                    }
                    BitmapFactory.decodeFile(config.imagePath)
                }
                if (image != null) {
                    predictor.setInputImage(image)
                    if (predictor.runModel(preprocess, visualize)) {
                        facesCount = predictor.getFacesCount()
                    }
                }
            } else {
                pendingResult?.error("-2","图片路径为空",null)
                clearMethodCallAndResult()
                return;
            }
        } else {
            pendingResult?.error("-1","识别模块未加载",null)
            clearMethodCallAndResult()
            return;
        }

        predictor.releaseModel()
        val endTime = System.currentTimeMillis()
        Log.i(TAG,"人脸识别耗时:${endTime - startTime}ms")
        pendingResult?.success(facesCount)
        clearMethodCallAndResult()
    }

    private fun clearMethodCallAndResult() {
        methodCall = null
        pendingResult = null
    }
}